package com.bolt.report.engine.fill;

import com.bolt.common.collection.IteratorUtil;
import com.bolt.convention.data.Record;
import com.bolt.report.definition.ReportDefinition;
import com.bolt.report.engine.BRGroupField;
import com.bolt.report.engine.model.DataRange;
import com.bolt.report.engine.model.GroupItem;
import com.bolt.report.engine.model.GroupTree;
import com.bolt.report.engine.model.ReportPrint;

import java.util.*;

public class FillGroupAggregate {

    private FillContext fillContext;


    public FillGroupAggregate(FillContext fillContext) {
        this.fillContext = fillContext;
    }

    public int indexOfGroup(String fieldName) {
        ReportPrint reportPrint = fillContext.getReportPrint();
        List<BRGroupField> groupFields = reportPrint.getGroup();
        int index = -1;
        for (int i = 0; i < groupFields.size(); i++) {
            BRGroupField groupField = groupFields.get(i);
            if (groupField.getName().equals(fieldName)) {
                index = i;
                break;
            }
        }
        return index;
    }

    public boolean isGroup(String fieldName) {
        ReportPrint reportPrint = fillContext.getReportPrint();
        List<BRGroupField> groupFields = reportPrint.getGroup();
        if (IteratorUtil.isEmpty(groupFields)) {
            return false;
        }
        boolean group = false;
        for (BRGroupField groupField : groupFields) {
            if (groupField.getName().equals(fieldName)) {
                group = true;
                break;
            }
        }
        return group;
    }


    public int computeRowSpan(GroupTree groupTree) {
        int rowSpan = groupTree.getDataSize();
        List<GroupTree> leafs = getLeaf(groupTree.getChildren());
        if (IteratorUtil.isNotEmpty(leafs)) {
            for (GroupTree leaf : leafs) {
                GroupItem groupInfo = leaf.getGroupItem();
                if (groupInfo.getHaveCalculator()) {
                    rowSpan++;
                }
            }
        }
        //总分组数
        return rowSpan;
    }

    public GroupTree get(Object groupKey, List<GroupTree> children) {
        GroupTree target = null;
        if (IteratorUtil.isEmpty(children)) {
            return target;
        }
        for (GroupTree groupTree : children) {
            if (groupTree.getGroupItem().getValue().equals(groupKey)) {
                target = groupTree;
                break;
            }
            if (target == null) {
                target = get(groupKey, groupTree.getChildren());

            }
        }
        return target;
    }

    public List<GroupTree> getLeaf(List<GroupTree> children) {
        List<GroupTree> leaf = new ArrayList<>();
        if (IteratorUtil.isEmpty(children)) {
            return leaf;
        }
        for (GroupTree groupTree : children) {
            if (IteratorUtil.isEmpty(groupTree.getChildren())) {
                leaf.add(groupTree);
            } else {
                List<GroupTree> subLeft = getLeaf(groupTree.getChildren());
                leaf.addAll(subLeft);
            }
        }
        return leaf;
    }

    public boolean ifCalculator(int groupIndex) {
        ReportDefinition definition = fillContext.getDefinition();
        ReportPrint reportPrint = fillContext.getReportPrint();
        int summarySize = definition.getGroupSummary().size();
        int groupSize = reportPrint.getGroup().size();
        if (summarySize == groupSize) {
            return true;
        } else {
            return groupIndex >= (groupSize - summarySize);
        }
    }


    public List<GroupTree> doGroup(List<Record> rawData, List<BRGroupField> groupFields, int groupIndex) {
        Map<Object, List<Record>> groupData = new LinkedHashMap<>();
        List<GroupTree> groupTrees = new ArrayList<GroupTree>();
        GroupItem groupItem = null;
        for (int dataIndex=0; dataIndex < rawData.size(); dataIndex++) {
            Record data = rawData.get(dataIndex);
            BRGroupField groupField = groupFields.get(groupIndex);
            Object value = data.get(groupField.getName());
            List<Record> groupRecord = groupData.get(value);
            if (groupRecord == null) {
                groupRecord = new ArrayList<>();
                groupRecord.add(data);
                groupData.put(value, groupRecord);
                DataRange range = new DataRange(groupRecord);
                groupItem = new GroupItem(value, range, fillContext.getDefinition().haveGroupSummary());
                GroupTree groupTree = new GroupTree(groupField);
                groupTree.setGroupItem(groupItem);

                groupTrees.add(groupTree);
            } else {
                groupRecord.add(data);
            }
        }
        if (groupIndex < groupFields.size() - 1) {
            Set<Object> keys = groupData.keySet();
            ++groupIndex;
            Iterator it = keys.iterator();
            for (int i = 0; it.hasNext(); i++) {
                Object key = it.next();
                List<GroupTree> children = doGroup(groupData.get(key), groupFields, groupIndex);
                Collections.sort(children);
                groupTrees.get(i).setChildren(children);
                groupTrees.get(i).setDepth(children.size());
            }
        }

        Collections.sort(groupTrees);
        return groupTrees;
    }


}